package threadjuc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zxl
 * @version 1.0
 * @date 2021/10/28 15:47
 */
public class Juc15 {
    /**
     * Volatile 轻量级的同步机制
     * 保证可见性
     * 不保证原子性
     * 禁止指令重排
     *
     * JMM的8大原子操作
     * 1、lock(锁定)：作用于主内存的变量，它把一个变量标识为一条线程独占的状态。
     * 2、unlock(解锁):作用于主内存的变量，它把一个处于锁定状态的变量释放出来，释放后的变量 才可以被其他线程锁定。
     * 3、read(读取):作用于主内存的变量，它把一个变量的值从主内存传输到线程的工作内存中，以 便随后的load动作使用。
     * 4、load(载入):作用于工作内存的变量，它把read操作从主内存中得到的变量值放入工作内存的 变量副本中。
     * 5、use(使用):作用于工作内存的变量，它把工作内存中一个变量的值传递给执行引擎，每当虚 拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
     * 6、assign(赋值):作用于工作内存的变量，它把一个从执行引擎接收的值赋给工作内存的变量， 每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
     * 7、store(存储):作用于工作内存的变量，它把工作内存中一个变量的值传送到主内存中，以便随 后的write操作使用。
     * 8、write(写入):作用于主内存的变量，它把store操作从工作内存中得到的变量的值放入主内存的变量中。
     */


    /**
     * 加volatile 可以通知线程 主内存的数据发生改变   不加线程则会一直等待
     */
    private volatile static int num1 = 0;

    /**
     * 不保证原子性
     */
    private volatile static int num2 = 0;
    /**
     * 将int改为AtomicInteger来保证原子性
     */
    private volatile static AtomicInteger num3 = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {
        test1();
        test2();
        test3();
    }

    /**
     * 测试volatile可见性
     * @throws InterruptedException
     */
    public static void test1() throws InterruptedException {
        new Thread(() -> {
            while (num1 == 0) {

            }
            System.out.println("结束");
        }).start();

        TimeUnit.SECONDS.sleep(2);
        num1 = 1;
        System.out.println("main");
    }

    /**
     * 测试volatile的不保证原子性
     */
    public static void test2(){
        //按道理应该为200000 实际上不是 所以不保证原子性
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 10000; j++) {
                    num2 ++;
                }
            }).start();
        }
        //当线程的数量不大于2是则其他的线程执行完毕 （默认的有两条线程 main 和 gc）
        while (Thread.activeCount()>2){

        }
        System.out.println(num2);
    }

    /**
     * 测试volatile 不加锁 如何保证原子性
     */
    public static void test3(){
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 10000; j++) {
                    num3.getAndIncrement(); //执行+1操作
                }
            }).start();
        }
        while (Thread.activeCount()>2){}
        System.out.println(num3);

    }

}
